home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
Games
/
net3d-0.08
/
object.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-06-22
|
30KB
|
1,222 lines
/* object.c
*
* Functions for displaying and manipulting objects
*/
#include "net3d.h"
double gtm=0.0; /* total time elapsed since */
/* start of game */
int vidcount=0; /* total number of vehicles */
/* created so far */
double vmax[TYPECOUNT]={79,35,25, /* maximum velocities for the */
1000,0,1000, /* different vehicle types. */
150,0,200, /* used if no maximum is given */
0,100,0,
200,0,0,};
/* The extra vehicles/objects list is used for storing objects
* created in-game, such as bullets, walls and new trees. It also
* stores vehicle definitions made in the vehicle files, for later
* instantiation.
*/
struct vehicle *evhead; /* head of the extra vehicles list */
struct object *eohead; /* head of the extra objects list */
vehicle_type playertype; /* vehicle type of player when
* they are wandering around on foot */
/* prints stats about the world */
void worldinfo(struct vehicle *vhead, struct object *ohead)
{
int vc=0; /* vehicles */
int oc=0; /* objects */
int fc=0; /* faces */
int pc=0; /* points */
for(vc=0; vhead; vhead=vhead->next,vc++)
;
for(oc=0; ohead; ohead=ohead->next,oc++) {
fc += ohead->fcount;
pc += ohead->pcount;
}
printf("%d vehicles\n%d objects\n%d faces\n%d points\n",vc,oc,fc,pc);
}
/* prints the vehicle list on screen (debugging purposes only) */
void dumpvehicles(struct vehicle *vhead)
{
int vc=0;
for(;vhead;vhead=vhead->next) {
struct object *obj;
int oc;
printf("\nvehicle %d\n",vc++);
printf("\tpartcount=%d\n",vhead->partcount);
printf("\tname=%s\n",vhead->name);
printf("\tcode=%s\n",vhead->code);
printf("\tangle=%f\n",vhead->angle);
printf("\tvelocity=%f\n",vhead->velocity);
printf("\tb-box %f %f %f to %f %f %f\n",vhead->bmin.x,
vhead->bmin.y,vhead->bmin.z,vhead->bmax.x,vhead->bmax.y,
vhead->bmax.z);
for(oc=0;oc < vhead->partcount;oc++) {
int i;
obj=vhead->parts[oc];
printf("\n\t\tobject %d\n",oc);
printf("\t\tpcount=%d fcount=%d\n",obj->pcount,obj->fcount);
printf("\t\tpos=%f %f %f\n",obj->pos.x,obj->pos.y,
obj->pos.z);
printf("\t\tcent=%f %f %f\n",obj->cent.x,obj->cent.y,
obj->cent.z);
printf("\t\tdist=%f\n",obj->dist);
printf("\t\tpoints : ");
for(i=0;i < obj->pcount;i++)
printf("%f %f %f ",obj->points[i].x,
obj->points[i].y,obj->points[i].z);
printf("\n");
printf("\t\tfaces : ");
for(i=0;i < obj->fcount;i++) {
struct polygon *pol;
int j;
pol=obj->faces+i;
printf("\n\t\t\tface %d\n",i);
printf("\t\t\tpcount=%d\n",pol->pcount);
printf("\t\t\tcolour=%ld\n",pol->colour);
printf("\t\t\ttype=%d\n",pol->type);
printf("\t\t\tpoints : ");
for(j=0;j < pol->pcount;j++)
printf("%d ",pol->vertices[j]);
printf("\n");
}
}
}
}
/* movevehicle - moves all the parts of a vehicle the distance they
* should move in a given time
*
* v - vehicle to move
* tm - travel time
*/
void movevehicle(struct vehicle *v, double tm, struct map *mp)
{
int i;
struct object **ob;
float xd,yd; /* direction of travel */
float xv,yv,zv=0.0; /* travel movement */
double rotz=0.0; /* rotation of vehicle */
struct point vcen;
int mx,my; /* map position */
float ht; /* height at that position */
bool changed=false; /* has bounding box changed */
float mxf, myf;
ob=v->parts;
vcen=ob[0]->pos;
/* find position on map, and height at that point
*/
xd=jcos(v->angle); yd=jsin(v->angle);
if (mp->size) {
mx = mxf = (vcen.x + (xd*20))/mp->size;
my = myf = (vcen.y + (yd*20))/mp->size;
if (mxf >= 0 && myf >= 0 && mx<mp->map_w && my<mp->map_h)
ht = mp->ht[mx][my];
else
ht = 0.0;
}
else {
ht = 0.0;
}
/* move forward, and drop down towards ground */
if ((v->velocity || v->climb || vcen.z!=ht) && v->type!=t_scenery) {
xv=xd*tm*v->velocity;
yv=yd*tm*v->velocity;
zv=tm*v->climb;
if (mp->ground && !v->flying && vcen.z>0)
v->climb -= tm*GRAVITY; /* fall to earth */
if (vcen.z < 0 && mp->ground) { /* keep above ground level */
zv = -vcen.z;
}
else if (vcen.z > v->max.altitude) { /* .. and below ceiling */
zv = v->max.altitude-vcen.z;
v->climb = 0.0;
}
shiftvehicle(v,xv,yv,zv);
/* if there is a maximum range, decrease and explode when
* range limit is reached.
*/
if (v->range) {
v->range -= tm*(dabs(v->velocity) + dabs(v->climb));
if (v->range < 0)
v->hp = -1;
}
}
/* slow down turn rate.
* NOTE!! - this can probably be removed.
*/
if (v->owner == o_player || v->owner == o_network) {
if (v->angle_vel > 0) {
v->angle_vel -= tm*dtor(FRICTION);
if (v->angle_vel < 0)
v->angle_vel = 0;
}
else if (v->angle_vel < 0) {
v->angle_vel += tm*dtor(FRICTION);
if (v->angle_vel > 0)
v->angle_vel = 0;
}
/* slow down turret turn rate */
for(i=0; i<v->partcount; i++) {
if (v->parts[i]->turret) {
if (v->parts[i]->angle_vel > 0) {
v->parts[i]->angle_vel -= tm*dtor(FRICTION);
if (v->parts[i]->angle_vel < 0)
v->parts[i]->angle_vel = 0;
}
else if (v->parts[i]->angle_vel < 0) {
v->parts[i]->angle_vel += tm*dtor(FRICTION);
if (v->parts[i]->angle_vel > 0)
v->parts[i]->angle_vel = 0;
}
}
}
}
/* rotate all parts of the vehicle.
* rotation is angle_vel radians per second.
*/
if (v->angle_vel != 0) {
changed=true;
rotz=tm*v->angle_vel;
v->angle += rotz;
if (v->angle < 0) /* keep angle within */
v->angle += 2*PI; /* 0 - 2PI */
else if (v->angle > 2*PI)
v->angle -= 2*PI;
for(i=0; i < v->partcount; i++)
rotatez(v->parts[i],rotz);
}
/* rotate separate sections as well (ie gun turrets) */
for(i=0; i<v->partcount; i++) {
v->parts[i]->angle += rotz;
if (v->parts[i]->angle_vel) {
double rotz2; /* rotation for part */
changed=true;
rotz2=tm*v->parts[i]->angle_vel;
rotatez(v->parts[i],rotz2);
v->parts[i]->angle += rotz2;
}
}
/* check for collision with ground hills, or with the ground if
* there is any.
*/
if (vcen.z < ht && (ht != 0.0 || mp->ground)) {
/* if a mountain has been hit, bounce back a bit */
if (v->type == t_bullet || v->type == t_shrapnel ||
v->type == t_seedpod) {
/* Some things are always destroyed on impact with
* the ground or a hill. */
v->hp = -1;
}
else {
if (ht) {
/* impact with a hill */
shiftvehicle(v,-xv*2,-yv*2,0);
v->hp -= (v->velocity < 5) ? 0 : 5;
}
else {
/* impact with the ground */
v->hp -= 5;
}
v->velocity = 0.0;
v->climb = 0.0;
v->angle_vel = 0.0;
v->bumped = True;
}
}
/* apply oscillation vectors */
for(i=0; i<v->partcount; i++) {
int j;
struct object *ob;
ob=v->parts[i];
for(j=0; j<ob->ocount; j++) {
float osc; /* amount oscillated (0-1) */
osc=ob->oscli[j].func(gtm*ob->oscli[j].rate +
ob->oscli[j].phase);
if (ob->oscli[j].axes & OSC_X_AXIS)
ob->oscli[j].pt->x = ob->oscli[j].init.x +
ob->oscli[j].ovec.x*osc;
if (ob->oscli[j].axes & OSC_Y_AXIS)
ob->oscli[j].pt->y = ob->oscli[j].init.y +
ob->oscli[j].ovec.y*osc;
if (ob->oscli[j].axes & OSC_Z_AXIS)
ob->oscli[j].pt->z = ob->oscli[j].init.z +
ob->oscli[j].ovec.z*osc;
changed=true;
}
}
/* apply spin factors */
if (v->xspin_vel) {
for(i=0; i < v->partcount; i++)
rotatex(v->parts[i],tm*v->xspin_vel);
changed=true;
}
if (v->yspin_vel) {
for(i=0; i < v->partcount; i++)
rotatey(v->parts[i],tm*v->yspin_vel);
changed=true;
}
if (v->zspin_vel) {
for(i=0; i < v->partcount; i++)
rotatez(v->parts[i],tm*v->zspin_vel);
changed=true;
}
/* slow down climb/dive, if appropriate.
*/
if (v->flying && v->type != t_bullet && v->type != t_shrapnel) {
if (v->climb > 0) {
v->climb -= tm*70;
if (v->climb < 0)
v->climb = 0;
}
if (v->climb < 0) {
v->climb += tm*70;
if (v->climb > 0)
v->climb = 0;
}
}
/* decrease reload time */
if (v->reload > 0)
v->reload -= tm;
/* increase time since last hit */
if (v->lasthit >= 0)
v->lasthit += tm;
/* decrease timer used in brain */
if (v->ftimer >= 0)
v->ftimer -= tm;
/* re-calculate bounding box if object has been rotated, oscillated
* or spun, changing the points */
if (changed)
calcbbox(v);
}
void movevehicles(struct vehicle **vh, struct object **oh, struct map *mp,
double gtime)
{
static double ctime=0.0; /* time at last call */
double ntime; /* time for this call */
struct vehicle *v,*va,*vb;
int tmp;
double tm;
struct vehicle *vnext;
/* find time since last movevehicles, from time passed in as parameter.
* This time comes from the server, making sure that all clients are
* synchronised.
*/
if (!ctime) {
ctime=gtime;
return;
}
ntime=gtime;
tm = ntime-ctime; /* time to move for this call */
/* check for vehicle-vehicle collisions. */
for(va=*vh; va; va=vnext) {
vnext = va->next;
if ((vb = collide(va,*vh))) {
/* check for transfer to another vehicle. */
if (enteredvehicle(va,vb)) {
/* va has entered vb */
va->transfer = vb->vid;
vb->owner = o_network;
vb->res = va->res;
vb->pnum = va->pnum;
freevehicle(va,vh,oh);
continue;
}
if (enteredvehicle(vb,va)) {
/* vb has entered va */
vb->transfer = va->vid;
va->owner = o_network;
va->res = vb->res;
va->pnum = vb->pnum;
freevehicle(vb,vh,oh);
continue;
}
/* check for resource collection */
if (va->type == playertype && vb->type == t_tree) {
va->res += 5;
freevehicle(vb,vh,oh);
continue;
}
if (vb->type == playertype && va->type == t_tree) {
vb->res += 5;
freevehicle(va,vh,oh);
continue;
}
/* check for collecting a bonus item */
if (va->type == t_weapon && (vb->owner == o_player ||
vb->owner == o_network)) {
vb->weapon = va->weapon;
freevehicle(va,vh,oh);
continue;
}
if (vb->type == t_weapon && (va->owner == o_player ||
va->owner == o_network)) {
va->weapon = vb->weapon;
freevehicle(vb,vh,oh);
continue;
}
/* check for collecting a munitions bonus */
if (va->type == t_munitions && (vb->owner == o_player ||
vb->owner == o_network)) {
vb->ammo += va->ammo;
freevehicle(va,vh,oh);
continue;
}
if (vb->type == t_munitions && (va->owner == o_player ||
va->owner == o_network)) {
va->ammo += va->ammo;
freevehicle(va,vh,oh);
continue;
}
/* damage both */
tmp = va->hp;
va->hp -= vb->hp;
vb->hp -= tmp;
/* record last hit time */
if (vb->type == t_bullet || vb->type == t_missile)
va->lasthit = 0.0;
else
va->bumped = True;
if (va->type == t_bullet || va->type == t_missile)
vb->lasthit = 0.0;
else
vb->bumped = True;
/* halt both vehicles, except for those that have been
* hit by a bullet.
*/
if (vb->type != t_bullet) {
va->velocity=0.0;
va->angle_vel=0.0;
}
if (va->type != t_bullet) {
vb->velocity=0.0;
vb->angle_vel=0.0;
}
/* If a bullet hits something, make sure that it is
* destroyed.
*/
if (va->type==t_bullet || va->type==t_missile ||
va->type == t_mine)
va->hp = -1;
if (vb->type==t_bullet || vb->type==t_missile ||
vb->type == t_mine)
vb->hp = -1;
/* kludge - if two vehicles with equal hp collide, then make
* them both explode, otherwise they will both end up on
* hp 0, and have no further effect on each other.
*/
if (!va->hp && !vb->hp) {
va->hp = vb->hp = -1;
}
/*
printf("%s has hit %s\n", va->code,vb->code);
*/
}
}
/* apply move to all vehicles, except for static and scenery types */
for(v=*vh; v; v = vnext) {
vnext = v->next;
if (v->type != t_scenery && v->type != t_static && v->type != t_mine)
movevehicle(v,tm,mp);
if (v->hp < 0) {
if (v->type == t_tree) {
/* If a tree is hit by something, then change it's
* type to static, so that it doesn't explode into
* seedpods.
*/
v->type = t_static;
}
explode(vh,oh,v);
}
}
/* increment game time, and store current time for this call */
gtm += ntime-ctime;
ctime=ntime;
}
void multpoints(struct object *ob, float mat[3][3])
{
struct point src;
int i;
/* multiply points */
for(i=0; i < ob->pcount; i++) {
src=ob->points[i];
mmult(&src,mat,ob->points+i);
}
/* multiply centre */
src=ob->cent;
mmult(&src,mat,&ob->cent);
/* multiply oscillation vectors, except for those applying to the
* position of an object instead of one of it's points.
*/
for(i=0; i<ob->ocount; i++) {
if (ob->oscli[i].pt != &ob->pos) {
src=ob->oscli[i].init;
mmult(&src,mat,&(ob->oscli[i].init));
}
src=ob->oscli[i].ovec;
mmult(&src,mat,&(ob->oscli[i].ovec));
}
}
void rotatez(struct object *ob, double rad)
{
float rotm[3][3]={{1,0,0},{0,1,0},{0,0,1}};
rotm[0][0]=(float)jcos(rad); rotm[1][0]=(float)jsin(rad);
rotm[0][1]=-rotm[1][0]; rotm[1][1]=rotm[0][0];
multpoints(ob,rotm);
}
void rotatex(struct object *ob, double rad)
{
float rotm[3][3]={{1,0,0},{0,1,0},{0,0,1}};
rotm[1][1]=(float)jcos(rad); rotm[2][1]=(float)jsin(rad);
rotm[1][2]=-rotm[2][1]; rotm[2][2]=rotm[1][1];
multpoints(ob,rotm);
}
void rotatey(struct object *ob, double rad)
{
float rotm[3][3]={{1,0,0},{0,1,0},{0,0,1}};
rotm[0][0]=(float)jcos(rad); rotm[2][0]=(float)-jsin(rad);
rotm[0][2]=-rotm[2][0]; rotm[2][2]=rotm[0][0];
multpoints(ob,rotm);
}
double gametime(void)
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv,&tz);
return tv.tv_sec+tv.tv_usec/1000000.0;
}
void makemap(struct object **ohead, struct map *mp)
{
int i,j;
/* generate ground objects (map starts at 0,0).
*/
for(i=0; i<mp->map_w; i++)
for(j=0; j<mp->map_h; j++) {
float c0,c1,c2,c3; /* corner heights */
struct point ps,ct;
struct point pts[4];
int facepts[4]={0,1,3,2};
struct polygon fcs[1]={{4,NULL,0,f_plane}};
/* heights at each polygon corner are the average of */
/* the heights of surrounding polygons */
c0=calcmap(i,j,mp);
c1=calcmap(i,j+1,mp);
c2=calcmap(i+1,j+1,mp);
c3=calcmap(i+1,j,mp);
mp->ht[i][j]=(c0+c1+c2+c3)/4.0; /* average polygon height */
if (mp->ht[i][j] == 0)
/* zero height */
continue;
/* each ground square is a single rectangle */
/* position */
ps.x=i*mp->size;
ps.y=j*mp->size;
ps.z=0.0;
/* centre */
ct.x=mp->size/2;
ct.y=mp->size/2;
ct.z=0.0;
/* points */
pts[0].x=0; pts[0].y=0; pts[0].z=c0;
pts[1].x=mp->size; pts[1].y=0; pts[1].z=c3;
pts[2].x=0; pts[2].y=mp->size; pts[2].z=c1;
pts[3].x=mp->size; pts[3].y=mp->size; pts[3].z=c2;
/* faces */
fcs[0].vertices=facepts;
fcs[0].colour=(mp->tcol*32)+31-(mp->gr[i][j]/mp->scale)*31;
addobject(ohead,ps,ct,NULL,4,1,pts,fcs);
(*ohead)->mx = i;
(*ohead)->my = j;
}
}
struct object *addobject(struct object **ohead, struct point pos, struct
point cent, struct vehicle *par, int pc, int fc, struct point *pts, struct
polygon *fcs)
{
struct object *no;
int i;
/* make a new object, containing deep copies of all the points/faces
* passed in as parameters */
no=(struct object *)calloc(1,sizeof(struct object));
no->next=(*ohead);
(*ohead)=no;
no->pcount=pc;
no->fcount=fc;
no->points=(struct point *)calloc(pc,sizeof(struct point));
no->cpoints=(struct point *)calloc(pc,sizeof(struct point));
no->ppoints=(XPoint *)calloc(pc,sizeof(XPoint));
memcpy(no->points,pts,pc*sizeof(struct point));
no->faces=(struct polygon *)calloc(fc,sizeof(struct polygon));
for(i=0; i<fc; i++) {
no->faces[i].pcount=fcs[i].pcount;
no->faces[i].colour=fcs[i].colour;
no->faces[i].type=fcs[i].type;
no->faces[i].vertices=calloc(fcs[i].pcount,sizeof(int));
memcpy(no->faces[i].vertices,fcs[i].vertices,fcs[i].pcount*
sizeof(int));
}
no->pos=pos;
no->cent=cent;
no->dist=0.0;
no->parent=par;
no->clockwise=true;
no->cvalid = false;
no->mightsave = false;
return no;
}
/* calculates the height of the bottom-left corner of map square x,y */
float calcmap(int x, int y, struct map *m)
{
float sum=0.0;
sum += (x < m->map_w && y < m->map_h ? m->gr[x][y] : 0.0);
sum += (x > 0 && y < m->map_h ? m->gr[x-1][y] : 0.0);
sum += (x > 0 && y > 0 ? m->gr[x-1][y-1] : 0.0);
sum += (x < m->map_w && y > 0 ? m->gr[x][y-1] : 0.0);
return sum/4.0;
}
/* explode - removes a vehicle from the game, possibly with a large
* explosion of shrapnel and several flaming fireballs.
*
* vhead - pointer to the head of the vehicle list
* ohead - pointer to the head of the object list
* t - the vehicle to explode
*/
void explode(struct vehicle **vhead, struct object **ohead, struct
vehicle *t)
{
int i,j;
struct point vcen;
/*
printf("exploding %s\n",t->code);
*/
vcen=t->parts[0]->pos; /* get position of vehicle */
if (t->type != t_shrapnel && t->type != t_seedpod) {
/* create blast fragments */
for(i=0; i<t->partcount; i++) {
int j;
struct object *ob;
ob=t->parts[i];
for(j=0; j<ob->fcount; j++) {
struct vehicle *nv;
struct point pts[MAX_POINTS_PER_OBJECT];
struct polygon fcs[1];
int facepts[MAX_POINTS_PER_FACE];
int pc,k;
struct point pos;
struct point cent={0,0,0};
/* create a new vehicle structure */
nv=(struct vehicle *)calloc(1,sizeof(struct vehicle));
nv->next=(*vhead); /* add to list */
*vhead=nv;
nv->partcount = 1;
nv->owner = o_game;
if (t->type == t_tree && rand()%SEEDCHANCE == 0)
nv->type = t_seedpod;
else
nv->type = t_shrapnel;
nv->weapon = w_none;
nv->flying = false;
nv->code = strdupe("shrapnel");
nv->name = strdupe("a blast fragment");
nv->velocity = rand()%40;
nv->climb = (rand()%60)-20;
nv->angle = dtor(rand()%360);
nv->hp = 1;
nv->alive = true;
nv->vid = vidcount++;
nv->parts = (struct object **)
calloc(1,sizeof(
struct object *));
nv->max.velocity = MAX_VELOCITY;
nv->max.angle_vel = MAX_ANGLE_VEL;
nv->max.altitude = MAX_ALTITUDE;
nv->transfer = -1;
nv->buildervid = -1;
nv->seed = strdupe(t->seed);
nv->pnum = -1;
nv->range = 200;
nv->stcount = 0;
nv->states = NULL;
nv->currentstate = -1;
nv->lasthit = 0.0;
/* extract the points from the original object
* which are used in the fragment.
*/
for(pc=0; pc<ob->faces[j].pcount; pc++) {
facepts[pc] = pc;
pts[pc] = ob->points[ob->faces[j].
vertices[pc]];
}
fcs[0].pcount=pc;
fcs[0].vertices=facepts;
fcs[0].colour=ob->faces[j].colour;
fcs[0].type=ob->faces[j].type;
/* change points in new object so that the
* minimum point is at 0,0,0
*/
pos=pts[0];
for(k=0; k<pc; k++) {
if (pos.x < pts[k].x)
pos.x=pts[k].x;
if (pos.y < pts[k].y)
pos.y=pts[k].y;
if (pos.z < pts[k].z)
pos.z=pts[k].z;
}
for(k=0; k<pc; k++) {
pts[k].x -= pos.x;
pts[k].y -= pos.y;
pts[k].z -= pos.z;
}
/* add the initial position of the victim to
* the position of the fragment.
*/
pos.x += ob->pos.x;
pos.y += ob->pos.y;
pos.z += ob->pos.z + 5;
/* give the fragment a random spin factor */
nv->xspin_vel = dtor(rand()%20);
nv->yspin_vel = dtor(rand()%20);
nv->zspin_vel = dtor(rand()%20);
/* create fragment object, which is one part of */
/* the original object */
nv->parts[0]=addobject(ohead,pos,cent,nv,pc,1,pts,fcs);
}
}
}
/* create several flaming fireballs when a vehicle explodes.
*/
if (t->type == t_tank || t->type == t_hover || t->type == t_fixedwing ||
t->type == t_gunsite || t->type == t_mine) {
for(i=0; i<FIREBALLS; i++) {
struct vehicle *nv;
char firename[15];
/* create the new fireball vehicle structure.
*/
nv = (struct vehicle *)calloc(1,sizeof(struct vehicle));
nv->parts = (struct object **)calloc(MAX_PARTS_PER_VEHICLE,
sizeof(struct object *));
nv->next = *vhead;
*vhead = nv;
/* copy a fireball from the extra vehicles list.
*/
sprintf(firename,"fireball%d",rand()%7 + 25);
copyvehicle(nv,findbycode(evhead,firename),ohead);
/* set attributes */
nv->code = strdupe("fireball");
nv->velocity = rand()%35;
nv->climb = (rand()%60)-20;
nv->angle = dtor(rand()%360);
nv->firer = NULL;
nv->vid = vidcount++;
nv->alive = true;
nv->range = 200;
/* position it near the dead vehicle */
for(j=0; j<nv->partcount; j++) {
addpts(nv->parts[j]->pos,t->parts[0]->pos,
&nv->parts[j]->pos);
nv->parts[j]->pos.z += 5;
}
calcbbox(nv);
}
}
/* create new trees when a seedpod hits the ground.
*/
if (t->type == t_seedpod) {
/* This is a seedpod. Create a tree at this spot.
*/
struct vehicle *nv;
int i;
struct point pos;
struct vehicle *seedv;
nv = (struct vehicle *)calloc(1,sizeof(struct vehicle));
nv->parts = (struct object **)calloc(MAX_PARTS_PER_VEHICLE,
sizeof(struct object *));
nv->next = *vhead;
*vhead = nv;
/* Copy the tree object */
seedv = findbycode(evhead,t->seed);
copyvehicle(nv,seedv,ohead);
nv->code=strdupe(seedv->code);
/* position it at the impact point of the seedpod */
pos = t->parts[0]->pos;
for(i=0; i<nv->partcount; i++) {
nv->parts[i]->pos.x += pos.x;
nv->parts[i]->pos.y += pos.y;
if (pos.z > 0)
nv->parts[i]->pos.z += pos.z;
}
/* set new tree's attributes */
nv->alive = true;
nv->vid = vidcount++;
calcbbox(nv);
}
freevehicle(t,vhead,ohead);
}
void freevehicle(struct vehicle *t, struct vehicle **vhead, struct
object **ohead)
{
int i,j;
struct object **opos;
struct vehicle **vpos;
for(vpos=vhead; *vpos != t; vpos=&((*vpos)->next))
; /* find pointer to to victim on list */
*vpos=t->next; /* route list around it */
/* free up all vehicle's objects */
for(i=0; i<t->partcount; i++) {
for(opos=ohead; *opos != t->parts[i]; opos=&((*opos)->next))
; /* find pointer to object on list */
*opos=t->parts[i]->next; /* re-route list */
/* free all the point lists of the polygons of the object */
for(j=0; j<t->parts[i]->fcount; j++) {
free(t->parts[i]->faces[j].vertices);
}
/* free the polygons of the object */
free(t->parts[i]->faces);
/* free oscillators */
free(t->parts[i]->oscli);
/* free points */
free(t->parts[i]->points);
free(t->parts[i]->cpoints);
free(t->parts[i]->ppoints);
free(t->parts[i]); /* free object */
}
/* free up the vehicle's brain */
for(i=0; i<t->stcount; i++) {
free(t->states[i].links);
}
if (t->states)
free(t->states);
/* totally free vehicle */
free(t->name);
free(t->parts);
free(t->code);
if (t->seed)
free(t->seed);
if (t->owner != o_player) {
free(t);
}
else
t->alive=false;
}
/* calculate the bounding box for a single vehicle, by finding the
* minimum and maximum x,y and z values for that vehicle's points
*/
void calcbbox(struct vehicle *v)
{
int i,j;
struct object *ob;
struct point pt;
/* initial min&max from first point in first object */
ob=v->parts[0];
v->bmax.x = v->bmin.x = ob->points[0].x + ob->pos.x;
v->bmax.y = v->bmin.y = ob->points[0].y + ob->pos.y;
v->bmax.z = v->bmin.z = ob->points[0].z + ob->pos.z;
/* loop through all points, and find min&max x,y & z values */
for(i=0; i<v->partcount; i++) {
ob=v->parts[i];
for(j=0; j<ob->pcount; j++) {
pt.x = ob->points[j].x + ob->pos.x;
pt.y = ob->points[j].y + ob->pos.y;
pt.z = ob->points[j].z + ob->pos.z;
/* find min & max x */
if (pt.x < v->bmin.x)
v->bmin.x=pt.x;
else if (pt.x > v->bmax.x)
v->bmax.x=pt.x;
/* ditto for y */
if (pt.y < v->bmin.y)
v->bmin.y=pt.y;
else if (pt.y > v->bmax.y)
v->bmax.y=pt.y;
/* and for z */
if (pt.z < v->bmin.z)
v->bmin.z=pt.z;
else if (pt.z > v->bmax.z)
v->bmax.z=pt.z;
}
}
}
/* calculate bounding boxes for the whole vehicle list */
void calcbboxes(struct vehicle *vhead)
{
for(; vhead; vhead=vhead->next)
calcbbox(vhead);
}
void shiftvehicle(struct vehicle *v, float x, float y, float z)
{
int i;
#if 1
for(i=0; i<v->partcount; i++) {
/* shift object positions */
v->parts[i]->pos.x += x;
v->parts[i]->pos.y += y;
v->parts[i]->pos.z += z;
}
#endif
/* shift bounding box */
v->bmin.x += x;
v->bmin.y += y;
v->bmin.z += z;
v->bmax.x += x;
v->bmax.y += y;
v->bmax.z += z;
}
void fire(struct vehicle **vhead, struct object **ohead, struct vehicle *f)
{
struct vehicle *nv;
struct point pos;
struct object *tur;
int i;
if (f->weapon==w_none || f->reload > 0 || !f->ammo)
return;
f->ammo--; /* decrease ammunition */
/* create a new vehicle structure, and add it to the list.
*/
nv = (struct vehicle *)calloc(1,sizeof(struct vehicle));
nv->parts = (struct object **)calloc(MAX_PARTS_PER_VEHICLE,
sizeof(struct object *));
nv->next = *vhead;
*vhead = nv;
nv->range=2000.0;
switch(f->weapon) {
case w_tracer:
copyvehicle(nv,findbycode(evhead,"tracer"),ohead);
nv->code=strdupe("tracer");
nv->velocity = max(f->velocity,0)+200;
f->reload = 0.3;
break;
case w_shell:
copyvehicle(nv,findbycode(evhead,"shell"),ohead);
nv->code = strdupe("shell");
nv->velocity = max(f->velocity,0)+100;
f->reload = 1.0;
break;
case w_bomb:
copyvehicle(nv,findbycode(evhead,"bomb"),ohead);
nv->code = strdupe("bomb");
nv->velocity = f->velocity;
f->reload = 1.0;
break;
case w_bullet:
copyvehicle(nv,findbycode(evhead,"bullet"),ohead);
nv->code = strdupe("bullet");
nv->velocity = max(f->velocity,0)+150;
f->reload = 0.2;
break;
case w_flame:
copyvehicle(nv,findbycode(evhead,"flame"),ohead);
nv->code = strdupe("flame");
nv->velocity = max(f->velocity,0)+100;
nv->range = 500;
f->reload = 2.5;
break;
case w_missile:
copyvehicle(nv,findbycode(evhead,"missile"),ohead);
nv->code = strdupe("missile");
nv->velocity = max(f->velocity,0)+100;
f->reload = 3.3;
/* follow vehicle locked onto by firer */
if (f->lock == -1)
nv->target = -2;
else
nv->target = f->lock;
break;
case w_chicken:
copyvehicle(nv,findbycode(evhead,"chicken"),ohead);
nv->code = strdupe("chicken");
nv->velocity = max(f->velocity,0)+150;
f->reload = 3.0;
break;
case w_plasmaballs:
copyvehicle(nv,findbycode(evhead,"plasmaballs"),ohead);
nv->code = strdupe("plasmaballs");
nv->velocity = max(f->velocity,0)+200;
f->reload = 1.0;
break;
case w_torpedo:
copyvehicle(nv,findbycode(evhead,"torpedo"),ohead);
nv->code = strdupe("torpedo");
nv->velocity = max(f->velocity,0)+100;
f->reload = 4.0;
/* follow vehicle locked onto by firer */
if (f->lock == -1)
nv->target = -2;
else
nv->target = f->lock;
break;
case w_none:
/* no weapon */
break;
}
/* set attributes of new projectile */
nv->owner=o_game;
nv->weapon=w_none;
nv->firer=f;
nv->alive=true;
nv->vid=vidcount++;
/* store missile's vid in firer */
f->missile = nv->vid;
/* find firing angle and fire position */
tur = findturret(f);
if (tur) {
nv->angle = tur->angle;
addpts(tur->pos,tur->cent,&pos);
}
else {
nv->angle=f->angle;
addpts(f->parts[0]->pos, f->parts[0]->cent,&pos);
}
/* add the firing position to all objects in the projectile vehicle */
for(i=0; i<nv->partcount; i++) {
nv->parts[i]->pos.x += pos.x;
nv->parts[i]->pos.y += pos.y;
nv->parts[i]->pos.z += pos.z;
}
/* add climb to projectile, so that it rises at the correct rate. */
nv->climb = tan(f->turret_ang)*nv->velocity;
/* rotate projectile to correct angle */
for(i=0; i<nv->partcount; i++) {
rotatey(nv->parts[i],-(f->turret_ang));
rotatez(nv->parts[i],nv->angle);
}
calcbbox(nv);
}
double dabs(double x)
{
return (x > 0 ? x : -x);
}
/* returns the square of the sin of it's argument */
double sinsq(double x)
{
double s;
s=jsin(x);
return s*s;
}
/* returns the sin of it's argument, scaled from 0 to 1 */
double sinhalf(double x)
{
return (jsin(x)+1.0)/2.0;
}
/* Read the array of strings in extras.c, and send them through a pipe to
* readfiles().
*/
void readextravehicles(void)
{
int fds[2];
pipe(fds);
if (!fork()) {
/* Read extra vehicles, and write them to the pipe.
*/
int i=0;
while(extras[i])
nprintf(fds[1],"%s\n",extras[i++]);
nprintf(fds[1],"end\n");
exit(0);
}
else {
readfile(&eohead,&evhead,fds[0],NULL);
}
printf("done reading extra vehicles\n");
}
/* Ejects the player from his/her current vehicle. */
void eject(struct vehicle **vhead, struct object **ohead, struct vehicle *v)
{
struct vehicle *nv;
struct point pos;
int i;
/* create a new vehicle structure */
nv = (struct vehicle *)calloc(1,sizeof(struct vehicle));
nv->parts = (struct object **)calloc(MAX_PARTS_PER_VEHICLE,
sizeof(struct object *));
nv->next = *vhead;
*vhead = nv;
/* fill it in with a copy of the lifeform vehicle from the bullets file */
copyvehicle(nv,findbycode(evhead,"player"),ohead);
nv->code = strdupe("player");
nv->velocity = 0;
nv->owner = v->owner;
nv->climb = 0;
nv->alive = true;
nv->vid = vidcount++;
nv->target = -1;
nv->reload = 0;
nv->lock = -1;
nv->res = v->res;
nv->pnum = v->pnum;
/* position the player near their old vehicle */
pos = v->bmax;
for(i=0; i<nv->partcount; i++) {
nv->parts[i]->pos.x += pos.x+6;
nv->parts[i]->pos.y += pos.y+6;
nv->parts[i]->pos.z += (v->bmin.z > 0 ? v->bmin.z : 0);
}
calcbbox(nv);
}
/* returns true if a player f can enter the vehicle v.
*/
bool enteredvehicle(struct vehicle *f, struct vehicle *v)
{
if ((f->owner == o_player || f->owner == o_network) &&
v->owner == o_none && f->type == findbycode(evhead,"player")->type)
return true;
else
return false;
}
/* rotatevehicle - rotate the given vehicle, and all it's parts.
*/
void rotatevehicle(struct vehicle *v, double newang)
{
int i;
for(i=0; i < v->partcount; i++)
rotatez(v->parts[i],newang - v->angle);
for(i=0; i<v->partcount; i++)
if (v->parts[i]->turret)
v->parts[i]->angle += (newang - v->angle);
v->angle = newang;
}
/* calculates the square of the distance from vehicle v1 to v2. */
float vehicledist(struct vehicle *v1, struct vehicle *v2)
{
float xd,yd,zd;
struct point vp1,vp2;
vp1 = v1->parts[0]->pos;
vp2 = v2->parts[0]->pos;
xd = vp1.x - vp2.x;
yd = vp1.y - vp2.y;
zd = vp1.z - vp2.z;
return xd*xd + yd*yd + zd*zd;
}
/* calculates the altitude difference from v2 to v1 */
double heightdiff(struct vehicle *v1, struct vehicle *v2)
{
return v1->parts[0]->pos.z - v2->parts[0]->pos.z;
}